package jp.dodododo.reloadable.file;

import java.io.File;
import java.io.FilenameFilter;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;

public class StateFile implements FilenameFilter {
	private File path;

	private List<StateFile> oldList;

	private long oldLastModified;

	private List<Pattern> ignoreFilePatternList;

	public StateFile(File file, List<Pattern> ignoreFilePatternList) {
		this.path = file;
		this.ignoreFilePatternList = ignoreFilePatternList;
		init();
	}

	public boolean isChange() {
		try {
			checkChange(this);
			return false;
		} catch (ChangedException e) {
			return true;
		}
	}

	private static void checkChange(StateFile file) throws ChangedException {
		if (file.path.lastModified() != file.oldLastModified) {
			throw new ChangedException();
		} else {
		}
		List<StateFile> oldList = file.oldList;
		File[] listFiles = file.path.listFiles(file);
		if (listFiles == null) {
			if (oldList.size() != 0) {
				throw new ChangedException();
			}
		} else if (oldList.size() != listFiles.length) {
			throw new ChangedException();
		}
		for (StateFile stateFile : oldList) {
			checkChange(stateFile);
		}
	}

	private void init() {
		oldList = new LinkedList<StateFile>();
		oldLastModified = path.lastModified();
		File[] files = path.listFiles();
		if (files == null) {
			return;
		}
		for (File file : files) {
			if (isIgnore(file) == false) {
				oldList.add(new StateFile(file, ignoreFilePatternList));
			}
		}
	}

	private boolean isIgnore(File file) {
		String fileName = file.getName();
		return isIgnore(fileName);
	}

	public boolean accept(File dir, String name) {
		if (isIgnore(name) == true) {
			return false;
		}
		return true;
	}

	private boolean isIgnore(String fileName) {
		for (Iterator<Pattern> iter = ignoreFilePatternList.iterator(); iter.hasNext();) {
			Pattern pattern = iter.next();
			if (pattern.matcher(fileName).matches() == true) {
				return true;
			}
		}
		return false;
	}

	public static class ChangedException extends Exception {
		private static final long serialVersionUID = 2631630787133769956L;
	}
}
